/**
 * @file   freertos_time.h
 * @author LightningSemi WLAN Team
 * Copyright (C) 2018 LightningSemi Technology Co., Ltd. All rights reserved.
 */

#ifndef _KERNEL_OS_FREERTOS_OS_TIME_H_
#define _KERNEL_OS_FREERTOS_OS_TIME_H_

#include "./FreeRTOS_Adapter/freertos_common.h"
#include "task.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Parameters used to convert the time values */
#define OS_MSEC_PER_SEC     1000U       /* milliseconds per second */
#define OS_USEC_PER_MSEC    1000U       /* microseconds per millisecond */
#define OS_USEC_PER_SEC     1000000U    /* microseconds per second */

/* system clock's frequency, OS ticks per second */
#define OS_HZ               configTICK_RATE_HZ

/* microseconds per OS tick (1000000 / OS_HZ) */
#define OS_TICK             (OS_USEC_PER_SEC / OS_HZ)

/** @brief Get the number of ticks since OS start */
/* Due to portTICK_TYPE_IS_ATOMIC is 1, calling xTaskGetTickCount() in ISR is
 * safe also.
 */
#define OS_GetTicks()       ((uint32_t)xTaskGetTickCount())

/** @brief Get the number of seconds since OS start */
#define OS_GetTime()        (OS_GetTicks() / OS_HZ)

/**
 * @brief Macros used to convert various time units to each other
 *     - Secs stand for seconds
 *     - MSecs stand for milliseconds
 *     - Ticks stand for OS ticks
 *     - Jiffies stand for OS jiffies, which is a synonym for OS ticks
 */
#define OS_SecsToTicks(sec)     ((uint32_t)(sec) * OS_HZ)
#define OS_MSecsToTicks(msec)   ((uint32_t)(msec) * (OS_USEC_PER_MSEC / OS_TICK))
#define OS_TicksToMSecs(t)      ((uint32_t)(t) / (OS_USEC_PER_MSEC / OS_TICK))
#define OS_TicksToSecs(t)       ((uint32_t)(t) / (OS_USEC_PER_SEC / OS_TICK))

#define OS_GetJiffies()         OS_GetTicks()
#define OS_SecsToJiffies(sec)   OS_SecsToTicks(sec)
#define OS_MSecsToJiffies(msec) OS_MSecsToTicks(msec)
#define OS_JiffiesToMSecs(j)    OS_TicksToMSecs(j)
#define OS_JiffiesToSecs(j)     OS_TicksToSecs(j)

/**
 * @brief Macros used to delay for the given time (milliseconds or seconds)
 */
#define OS_MsDelay(msec)         vTaskDelay((TickType_t)OS_MSecsToTicks(msec))
#define OS_Delay(sec)            OS_MsDelay((sec) * OS_MSEC_PER_SEC)
#define OS_SecDelay(sec)         OS_Delay(sec)

/**s
 * @brief Macros used to compare time values
 *
 *  These inlines deal with timer wrapping correctly. You are
 *  strongly encouraged to use them
 *  1. Because people otherwise forget
 *  2. Because if the timer wrap changes in future you won't have to
 *     alter your code.
 *
 * OS_TimeAfter(a,b) returns true if the time a is after time b.
 *
 * Do this with "<0" and ">=0" to only test the sign of the result. A
 * good compiler would generate better code (and a really good compiler
 * wouldn't care). Gcc is currently neither.
 */
#define OS_TimeAfter(a, b)              ((int32_t)(b) - (int32_t)(a) < 0)
#define OS_TimeBefore(a, b)             OS_TimeAfter(b, a)
#define OS_TimeAfterEqual(a, b)         ((int32_t)(a) - (int32_t)(b) >= 0)
#define OS_TimeBeforeEqual(a, b)        OS_TimeAfterEqual(b, a)

/** @brief Macros used to generate fake random 32-bit value */
/* The fake random 32-bit value is generated by combining OS ticks and
 * the value of SysTick current value register.
 */
#define OS_Rand32()                                                 \
    ((uint32_t)(((*((volatile uint32_t *)0xE000E018)) & 0xffffff) | (OS_GetTicks() << 24)))

__STATIC_INLINE TickType_t OS_CalcWaitTicks(OS_Time_t msec)
{
	TickType_t tick;
	if (msec == OS_WAIT_FOREVER) 
	{
		tick = portMAX_DELAY;
	} 
	else if (msec != 0) 
	{
		tick = OS_MSecsToTicks(msec);
		if (tick == 0){
			tick = 1;
		}			
	}
	else 
	{
		tick = 0;
	}
	return tick;
}

#ifdef __cplusplus
}
#endif

#endif /* _KERNEL_OS_FREERTOS_OS_TIME_H_ */
